package eerbaar.server.serializer.internal;

import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Stack;

import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartElement;

import eerbaar.shared.exceptions.GameException;
import eerbaar.shared.tree.IAttribute;
import eerbaar.shared.tree.IAttributes;
import eerbaar.shared.tree.INode;
import eerbaar.shared.tree.NodeIterator;


public class ConvertToXml {

    private List<Attribute> assignAttributes(XMLEventFactory eventFactory,
            INode node) {
        List<Attribute> attributeList = new ArrayList<Attribute>();
        IAttributes attributes = node.getAttributes();
        for (IAttribute<?> a : attributes) {

            Object value = a.getValue();
            if (value != null) {
                String localName = a.getKey();
                Attribute attribute = eventFactory.createAttribute(localName,
                        value.toString());
                attributeList.add(attribute);
            }
        }
        return attributeList;
    }

    public String convert(INode inNode) throws GameException {

        String result = null;

        try {
            result = privateConvert(inNode);
        } catch (XMLStreamException e) {
            e.printStackTrace();
            throw new GameException(e);
        }

        return result;
    }

    public String privateConvert(INode inNode) throws XMLStreamException {

        Stack<INode> queue = new Stack<INode>();

        StringWriter stringWriter = new StringWriter();
        XMLEventWriter eventWriter = XMLOutputFactory.newInstance()
                .createXMLEventWriter(stringWriter);
        XMLEventFactory eventFactory = XMLEventFactory.newInstance();

        NodeIterator iterator = new NodeIterator(inNode);
        while (iterator.hasNext()) {

            NodeIterator.Result r = iterator.next();
            INode node = r.node;

            int xmlDepth = r.depth;
            int nodeDepth = queue.size();
            while (xmlDepth < nodeDepth) {

                INode lastNode = queue.pop();
                nodeDepth = queue.size();

                String key = lastNode.getPayload().getKey();

                EndElement codeEE = eventFactory.createEndElement("", "", key);
                eventWriter.add(codeEE);
            }

            queue.push(node);

            String key = node.getPayload().getKey();
            List<Attribute> attributeList = assignAttributes(eventFactory, node);

            QName name = new QName(key);
            StartElement startElement = eventFactory.createStartElement(name,
                    attributeList.iterator(), Collections.emptyList()
                            .iterator());
            eventWriter.add(startElement);
        }

        while (queue.size() > 0) {
            INode lastNode = queue.pop();
            String key = lastNode.getPayload().getKey();
            QName name = new QName(key);
            EndElement codeEE = eventFactory.createEndElement(name, null);
            eventWriter.add(codeEE);
        }

        return stringWriter.toString();
    }
}
